package cn.xo68.boot.webgather.job.txtnovel;


import cn.xo68.boot.groovyscript.engine.GroovyScriptExcutor;
import cn.xo68.boot.job.JobProvider;
import cn.xo68.boot.job.entity.DistributedLock;
import cn.xo68.boot.job.entity.QuartzJob;
import cn.xo68.boot.job.jdbcstore.lock.DistributedLockManager;
import cn.xo68.boot.webgather.common.GatherStatusEnums;
import cn.xo68.boot.webgather.document.txtnovel.TxtNovelDoc;
import cn.xo68.boot.webgather.document.txtnovel.TxtNovelDownloadConfig;
import cn.xo68.boot.webgather.http.DownloadHttpCallback;
import cn.xo68.boot.webgather.http.HttpClient;
import cn.xo68.boot.webgather.resolve.ContentResolve;
import cn.xo68.boot.webgather.resolve.ResolveFactory;
import cn.xo68.boot.webgather.service.txtnovel.TxtNovelGatherService;
import cn.xo68.core.date.DateTime;
import cn.xo68.core.util.JsonUtil;
import cn.xo68.core.util.ShardByMurMurHash;
import cn.xo68.core.util.StringTools;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.Map;


@ConditionalOnMissingBean(name = "txtNovelDownloadJobProvider")
@Component("txtNovelDownloadJobProvider")
public class TxtNovelDownloadJobProvider implements JobProvider {

    private final static Logger logger = LoggerFactory.getLogger(TxtNovelDownloadJobProvider.class);


    @Autowired(required = false)
    private ResolveFactory resolveFactory;
    @Autowired
    private JsonUtil jsonUtil;
    @Autowired(required = false)
    private TxtNovelGatherService txtNovelGatherService;

    @Autowired
    private DistributedLockManager distributedLockManager;


    @Override
    public void execute(JobExecutionContext context, QuartzJob quartzJob) {
        TxtNovelDownloadConfig txtNovelDownloadConfig =jsonUtil.parse(quartzJob.getParameters(), TxtNovelDownloadConfig.class);
        logger.debug("txtNovelDownloadConfig:  {}", txtNovelDownloadConfig);
        if(txtNovelDownloadConfig ==null){
            logger.error("参数不正确或为空");
            return;
        }
        String lockKey="lock:txtNovelDownloadJobProvider";

        DistributedLock lock= distributedLockManager.tryLock(lockKey, "", 30*1000, 1*1000);
        if(lock==null){
            logger.info("没有申请到锁，lock_key: {}", lockKey);
            return;
        }
        Page<TxtNovelDoc> docs=null;
        try{
            docs = txtNovelGatherService.findTop(GatherStatusEnums.WAITGATHING, txtNovelDownloadConfig.getBatchGatherCount());
            docs.getContent().forEach(gatherDoc ->{
                gatherDoc.setGatherStatus(GatherStatusEnums.GATHING);
                gatherDoc.setContentStartGatherTime(DateTime.Now().getDate());
            });
            txtNovelGatherService.saves(docs.getContent());
            logger.debug("开始本次内容采集:{}，还剩余: {} 条,本次采集: {}",quartzJob.getJobGroup() +"-"+ quartzJob.getJobName(),docs.getTotalElements(), docs.getContent().size());

        }finally {
            distributedLockManager.unLock(lock.getLockKey());
        }

        ShardByMurMurHash shardByMurMurHash= new ShardByMurMurHash(128);

        if(docs!=null && docs.hasContent() && docs.getContent().size() > 0) {
            docs.getContent().forEach(txtNovelDoc->{
                try{
                    gatherPage(quartzJob,txtNovelDoc,txtNovelDownloadConfig, shardByMurMurHash);

                    txtNovelDoc.setGatherStatus(GatherStatusEnums.FINISH);
                    txtNovelDoc.setContentEndGatherTime(DateTime.Now().getDate());
                    txtNovelGatherService.save(txtNovelDoc);
                }catch (Throwable ex){
                    txtNovelDoc.setGatherStatus(GatherStatusEnums.FAIL);
                    txtNovelDoc.setContentEndGatherTime(DateTime.Now().getDate());
                    txtNovelGatherService.save(txtNovelDoc);
                }

            });
        }
    }

    private void gatherPage(QuartzJob quartzJob, TxtNovelDoc txtNovelDoc,TxtNovelDownloadConfig txtNovelDownloadConfig, ShardByMurMurHash shardByMurMurHash) throws Throwable {
        String urlStr= txtNovelDoc.getNovelUrl();

        ContentResolve contentResolveDefault=resolveFactory.getContentResolve(txtNovelDoc.getTxtNovelLinkGatherConfig().getResolveType(), urlStr);

        Map<String,Object> vars= new LinkedHashMap<>();
        vars.put("contentResolveDefault",contentResolveDefault);
        vars.put("txtNovelDoc",txtNovelDoc);
        vars.put("logger",logger);

       Object returnValue = GroovyScriptExcutor.excute(txtNovelDoc.getTxtNovelLinkGatherConfig().getInfoResolveScript(),vars);


        //"http://www.555x.org/home/down/txt/id/"+ sourceNovelId
        if(StringTools.isEmpty((String) returnValue)){
            logger.error("采集异常，无法识别源编码，名称： {}", txtNovelDoc.getNovelName());
            txtNovelDoc.setContentEndGatherTime(DateTime.Now().getDate());
            txtNovelDoc.setGatherStatus(GatherStatusEnums.FAIL);
            txtNovelGatherService.save(txtNovelDoc);
            return;
        }
        String downloadUrl= (String) returnValue;

        String saveFileName = txtNovelDoc.getNovelName() + ".txt";
        String saveDir = txtNovelDownloadConfig.getSaveFolder() + shardByMurMurHash.calculate(txtNovelDoc.getNovelName());
        DownloadHttpCallback downloadHttpCallback = new DownloadHttpCallback( saveFileName,saveDir);
        downloadHttpCallback.setMaxRate(txtNovelDownloadConfig.getMaxDownloadRate());
        HttpClient.getInstance().get(downloadUrl, null, downloadHttpCallback);
        if(downloadHttpCallback.hasException()){
            //throw stringHttpCallback.getException();
            throw new RuntimeException("",downloadHttpCallback.getException());
        }


        txtNovelDoc.setContentEndGatherTime(DateTime.Now().getDate());
        txtNovelDoc.setGatherStatus(GatherStatusEnums.FINISH);

        if(!logger.isTraceEnabled() && logger.isDebugEnabled()){
           logger.debug("[{}]下载完成",txtNovelDoc.getNovelName());
        }
        logger.trace("[{}]下载完成,doc: {}",txtNovelDoc.getNovelName(), txtNovelDoc);
        txtNovelGatherService.save(txtNovelDoc);
    }
}
